package com.chaos.auth.config.granter.admin;

import cn.hutool.core.util.ObjectUtil;
import com.chaos.auth.api.dto.token.AdminAuthenticationToken;
import com.chaos.auth.service.userdetails.AdminByUsernameDetailsService;
import com.chaos.framework.model.serivce.RedisService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.Map;

/**
 * @author yjp
 * @date 2024/5/30
 */
@Slf4j
public class AdminByUsernameAuthenticationProvider implements AuthenticationProvider {
    private PasswordEncoder passwordEncoder;

    private AdminByUsernameDetailsService adminByUsernameDetailsService;

    @Setter
    private RedisService redisService;


    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Map<String, String> details = (Map<String, String>) authentication.getDetails();
        String username = details.get("username");
        String password = details.get("password");

        Assert.notNull(username, "用户名不能为空");
        Assert.notNull(password, "密码不能为空");

        String tenantIdString = details.get("tenantId");

        String username_lock = "authenticate:username:" + username;
        Object count = redisService.get(username_lock);
        int c;
        if (!ObjectUtil.isEmpty(count)) {
            c = (int) count;
            if (c >= 5) {
                throw new DisabledException("账户已被锁定");
            }
        } else {
            c = 0;
        }
        UserDetails userDetails;
        if (!ObjectUtil.isEmpty(tenantIdString)) {
            Long tenantId = Long.valueOf(tenantIdString);
            Assert.notNull(tenantId, "租户不能为空");
            userDetails = adminByUsernameDetailsService.loadUserByUsername(username, tenantId);
        } else {
            userDetails = adminByUsernameDetailsService.loadUserByUsername(username);
        }

        if (!passwordEncoder.matches(password, userDetails.getPassword())) {
            redisService.set(username_lock, ++c, 10 * 60);
            throw new DisabledException("账号或密码不正确");
        }
        AdminAuthenticationToken result = new AdminAuthenticationToken(userDetails.getAuthorities(), userDetails);
        result.setDetails(authentication.getDetails());
        return result;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return AdminAuthenticationToken.class.isAssignableFrom(authentication);
    }

    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
        this.passwordEncoder = passwordEncoder;
    }

    public void setUserDetailsService(AdminByUsernameDetailsService userDetailsService) {
        this.adminByUsernameDetailsService = userDetailsService;
    }

}
